import type { Hashable } from "./Common";

export class ID implements Hashable {
    constructor(
        public readonly value: string,
        public readonly alias: Set<string>) { };

    matches(name: string): boolean {
        return this.value == name || this.alias.has(name);
    }

    hashcode(): string {
        return JSON.stringify([this.value, Array.from(this.alias)]);
    }

    equals(x: this): boolean {
        return this.value == x.value
            && JSON.stringify(this.alias) == JSON.stringify(x.alias);
    }
}

export class ClassID implements Hashable {
    constructor(
        public readonly name: string,
        public readonly determiner: string,
        public readonly alias: Set<string>,
        public readonly parent: (() => ClassID) | null = null) {};

    matches(name: string | ClassID): boolean {
        if (name instanceof ClassID)
            return this.equals(name as this);
        else
            return this.name == name || this.alias.has(name);
    }

    matchesExtended(name: string | ClassID): boolean {
        if (name instanceof ClassID)
            return this.equals(name as this) 
                || (this.parent != null ? this.parent().matchesExtended(name) : false);
        
        if (this.matches(name)) return true;
        return this.parent == null ? false : this.parent().matches(name);
    }
    
    hashcode(): string {
        return JSON.stringify([this.name, this.determiner, Array.from(this.alias)])
    }

    equals(x: this): boolean {
        if (this.parent == null && x.parent != null) return false;
        return this.hashcode() == x.hashcode()
            && ((this.parent != null && x.parent != null)
                ? this.parent().equals(x.parent()) : true);
    }
}
